#region Header

// MS codename Velocity Distributed Cache Extensions.
// (c) 2009

#endregion


#region Usings

using System;
using System.Collections.Generic;

#endregion


namespace Caching.Extensions.Core.Impl
{
    /// <summary>
    /// Local cache performance counter names.
    /// </summary>
    public static class LocalCachePerfCounters
    {
        /// <summary>
        /// Local cache category name.
        /// </summary>
        public const string CategoryName = "LocalCache";
        /// <summary>
        /// Hits / interval.
        /// </summary>
        public const string HitsPerInterval = "HitsPerInterval";
        /// <summary>
        /// Total number of local cache hits.
        /// </summary>
        public const string HitsTotal = "HitsTotal";
        /// <summary>
        /// Local cache misses.
        /// </summary>
        public const string MissesPerInterval = "MissesPerInterval";
        /// <summary>
        /// Total number of local cache misses.
        /// </summary>
        public const string MissesTotal = "MissesTotal";
        /// <summary>
        /// Local cache puts per interval.
        /// </summary>
        public const string PutsPerInterval = "PutsPerInterval";
        /// <summary>
        /// Local cache removes per interval.
        /// </summary>
        public const string RemovesPerInterval = "RemovesPerInterval";
        /// <summary>
        /// Total number of local cache clean-ups.
        /// </summary>
        public const string CleanupsTotal = "CleanupsTotal";
        /// <summary>
        /// Total number of local cache errors.
        /// </summary>
        public const string ErrorsTotal = "ErrorsTotal";
        /// <summary>
        /// Local cache errors per interval.
        /// </summary>
        public const string ErrorsPerSecond = "ErrorsPerSecond";
    }


    /// <summary>
    /// Remote cache performance counter names.
    /// </summary>
    public static class RemoteCachePerfCounters
    {
        /// <summary>
        /// Category name.
        /// </summary>
        public const string CategoryName = "SmartCache: Remote cache";

        /// <summary>
        /// Remote cache errors per interval.
        /// </summary>
        public const string ErrorsPerSecond = "Errors/second";                      // conf
        /// <summary>
        /// Total number of remote cache errors.
        /// </summary>
        public const string ErrorsTotal = "Errors total";                           // conf
        /// <summary>
        /// Total number of remota cache region operations (create/remove).
        /// </summary>
        public const string RegionOperationsTotal = "Region operations";            // conf
        /// <summary>
        /// Number of remote cache removals per second.
        /// </summary>
        public const string RemovesPerSecond = "Removes/second";                    // conf

        /// <summary>
        /// Remote cache PUTs per second.
        /// </summary>
        public const string PutsPerSecond = "Puts/second";                          // conf
        /// <summary>
        /// remote cache hits per second.
        /// </summary>
        public const string HitsPerSecond = "Hits/second";                          // conf
        /// <summary>
        /// Total number of remote cache hits.
        /// </summary>
        public const string HitsTotal = "Hits";                                     // conf
        /// <summary>
        /// Remote cache misses per second.
        /// </summary>
        public const string MissesPerSecond = "Misses/second";                      // conf
        /// <summary>
        /// Total number of remote cache misses.
        /// </summary>
        public const string MissesTotal = "Misses";                                 // conf
        /// <summary>
        /// QueryUpdate hits (not updated) per second.
        /// </summary>
        public const string QueryUpdateHitsPerSecond = "QueryUpdate Hits/second";   // conf
        /// <summary>
        /// QueryUpdate misses (item updated) per second.
        /// </summary>
        public const string QueryUpdateMissesPerSecond = "QueryUpdate Misses/second";   // conf
    }


    internal class SmartCachePerformanceMonitorSink : ISmartCacheEventSink
    {
        private readonly LocalCachePerformanceLogger m_localCacheLogger;
        private readonly IDictionary<string, RemoteCachePerformanceLogger> m_remoteCacheLoggers;


        public SmartCachePerformanceMonitorSink()
        {
            m_localCacheLogger = new LocalCachePerformanceLogger();
            m_remoteCacheLoggers = new Dictionary<string, RemoteCachePerformanceLogger>();
        }


        public void LocalCacheError(object localCache, SmartCacheExceptionNotification notification)
        {
            m_localCacheLogger.OnError();
        }


        public void RemoteCacheError(object remoteCache, SmartCacheExceptionNotification notification)
        {
            GetRemoteCacheLogger(notification.CacheName).OnError();
        }


        public void LocalCacheItemNotification(object localCache, SmartCacheLocalItemNotification notification)
        {
            switch (notification.Operation)
            {
                case LocalCacheItemOperation.Hit:
                    m_localCacheLogger.OnCacheHit();
                    break;
                case LocalCacheItemOperation.Miss:
                    m_localCacheLogger.OnCacheMiss();
                    break;
                case LocalCacheItemOperation.Put:
                    m_localCacheLogger.OnAdd();
                    break;
                case LocalCacheItemOperation.Remove:
                    m_localCacheLogger.OnRemove();
                    break;
                default:
                    throw new ArgumentOutOfRangeException("notification.Operation");
            }
        }


        public void RemoteCacheItemOperation(object remoteCache, SmartCacheRemoteItemNotification notification)
        {
            RemoteCachePerformanceLogger logger = GetRemoteCacheLogger(notification.Key.CacheName);
            switch (notification.Operation)
            {
                case SmartCacheItemOperation.Hit:
                    logger.OnHit();
                    break;
                case SmartCacheItemOperation.Miss:
                    logger.OnMiss();
                    break;
                case SmartCacheItemOperation.QueryUpdateHit:
                    logger.OnQueryUpdateHit();
                    break;
                case SmartCacheItemOperation.QueryUpdateMiss:
                    logger.OnQueryUpdateMiss();
                    break;
                case SmartCacheItemOperation.Put:
                    logger.OnPut();
                    break;
                case SmartCacheItemOperation.Remove:
                    logger.OnRemove();
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }


        private RemoteCachePerformanceLogger GetRemoteCacheLogger(string cacheName)
        {
            RemoteCachePerformanceLogger logger;
            lock (this)
            {
                if (m_remoteCacheLoggers.TryGetValue(cacheName, out logger) == false)
                {
                    logger = new RemoteCachePerformanceLogger(cacheName, false);
                    m_remoteCacheLoggers[cacheName] = logger;
                }
            }
            return logger;
        }


        public void RegionOperation(object remoteCache, SmartCacheRegionNotification notification)
        {
            RemoteCachePerformanceLogger logger = GetRemoteCacheLogger(notification.CacheName);
            switch (notification.Operation)
            {
                case SmartCacheRegionOperation.Create:
                    logger.OnCreateRegion();
                    break;
                case SmartCacheRegionOperation.Remove:
                    logger.OnRemoveRegion();
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }


        public void LocalCacheCleanup(object localCache, SmartCacheCleanupNotification info)
        {
            m_localCacheLogger.OnCleanup();
        }
    }
}